/**
 * @file SIPServer.cpp
 * @author Derek Liu (yjkhtddx@sina.com)
 * @brief SIP服务器
 * @version 0.0.1
 * @date 2020-07-16
 * 
 * @coryright Copyright Sci-Tech Laboratories (c) 2020
 * 
 */

#include "SIPServer.hpp"
#include "eXosip2/eXosip.h"
#include "STL_Log.hpp"
#include <netinet/in.h>
#include "STL_Thread.hpp"
#include "STL_ThreadPool.hpp"
#include <functional>
#include "defs.hpp"
#include "EventMgr.hpp"

SIPServer::SIPServer()
    : m_sipPort(5060), m_eventId(1000000000), m_excontext(nullptr)
{
}

SIPServer::~SIPServer() = default;

SIPServer *SIPServer::instance()
{
    static SIPServer server;
    return &server;
}

void SIPServer::setLocalConfig(const std::string &sip_id, const std::string &host, uint16_t port)
{
    m_sipId = sip_id;
    m_sipHost = host;
    m_sipPort = port;
}

void SIPServer::start(const std::string &user_agent)
{
    int ret = eXosip_listen_addr(m_excontext, IPPROTO_UDP, m_sipHost.c_str(), m_sipPort, AF_INET, 0);
    if (ret != OSIP_SUCCESS)
    {
        eXosip_quit(m_excontext);
        stl::error("eXosip_listen_addr failed, ret: ", ret);
        return;
    }

    stl::debug("eXosip start listen[UDP] %s:%d", m_sipHost.c_str(), m_sipPort);

    if (user_agent.length() > 0)
        eXosip_set_user_agent(m_excontext, user_agent.c_str());

    stl::ThreadTask recvTask = std::bind(&SIPServer::DoReceiveEvents, this);
    stl::ThreadTask procTask = std::bind(&SIPServer::DoProcessEvents, this);

    stl::ThreadPool::instance()->pushTask(recvTask);
    stl::ThreadPool::instance()->pushTask(procTask);
}

// int SIPServer::DoReceiveEvents() // 测试丢包，结论：dahua 94秒内发送11个注册UDP包, exosip对udp包进行了去重处理，并非丢包。
// {
//     for (;;)
//     {
//         eXosip_event_t *exosip_event;

//         exosip_event = eXosip_event_wait(m_excontext, 0, 50);
//         stl::debug("OnReceiveEvents1");
//         //    eXosip_lock(m_excontext);
//         //    eXosip_automatic_action(m_excontext);
//         //    eXosip_unlock(m_excontext);

//         if (exosip_event == nullptr)
//             continue;

//         stl::debug("OnReceiveEvents2######################");

//         sip_event_sptr sipg_event = new_event(m_excontext, exosip_event);
//         if (nullptr == sipg_event)
//             continue;

//         stl::debug("OnReceiveEvents3");
//         m_eventQueue.Push(sipg_event);
//         stl::debug("Push event: %s, id=%d to queue successfully", sipg_event->name, sipg_event->id);
//     }
//     return 0;
// }

int SIPServer::DoReceiveEvents() // TODO BUG：使用线程池丢包严重
{
    eXosip_event_t *exosip_event;

    exosip_event = eXosip_event_wait(m_excontext, 0, 1);
    
    // stl::debug("OnReceiveEvents");

    //    eXosip_lock(m_excontext);
    //    eXosip_automatic_action(m_excontext);
    //    eXosip_unlock(m_excontext);

    if (exosip_event == nullptr)
        return 0;
    
    // stl::debug("OnReceiveEvents #######################################################");
    
    sip_event_sptr sipg_event = new_event(m_excontext, exosip_event);
    if (nullptr == sipg_event)
        return 0;

    stl::debug("OnReceiveEvents[%s]", sipg_event->name);

    m_eventQueue.Push(sipg_event);
    stl::debug("Push event: %s, id=%d to queue successfully", sipg_event->name, sipg_event->id);
    return 0;
}

int SIPServer::DoProcessEvents()
{
    const char *event_name;
    uint64_t event_id;

    sip_event_sptr sipg_event;
    if (!m_eventQueue.Pop(sipg_event))
        return 0;

    event_name = sipg_event->name;
    event_id = sipg_event->id;

    stl::debug("OnProcessEvents[%s]", sipg_event->name);

    sipg_event->proc(sipg_event);
    eXosip_event_free(sipg_event->exevent);
    return 0;
}

void SIPServer::init()
{
    m_excontext = eXosip_malloc();
    int ret = eXosip_init(m_excontext);
    if (ret != OSIP_SUCCESS)
    {
        stl::error("eXosip_init failed, ret=%d", ret);
    }
    stl::info("eXosip_init successfully!");
}

void SIPServer::quit()
{
    eXosip_quit(m_excontext);
}

sip_event_sptr SIPServer::new_event(eXosip_t *exosip_context, eXosip_event_t *exosip_event)
{
    if (exosip_event == nullptr)
        return nullptr;

    if (exosip_event->type < EXOSIP_REGISTRATION_SUCCESS || exosip_event->type > EXOSIP_NOTIFICATION_GLOBALFAILURE)
        return nullptr;

    sip_event_sptr event(new sip_event_t); // = std::make_shared(SipEvent)();

    EventMgr::EventNameProcPair pair = m_eventHandle.getEventProc(exosip_event->type);
    if (pair.name == nullptr)
        return nullptr;

    event->name = pair.name;
    event->proc = pair.proc;
    event->excontext = exosip_context;
    event->exevent = exosip_event;
    event->id = m_eventId++;

    return event;
}
